using System;
using System.Collections.Generic;
using System.Linq;
using FireStarterModeller.BO;
using Habanero.BO;

namespace FireStarterModeller.Logic.Wizards
{
    public class DMClassDeleter : IDeleter
    {
        public IDMClass ClassDM { get; private set; }

        public IEnumerable<IDMRelationship> AllRelationshipWithRelatedFKs
        {
            get
            {
                return this.ClassDM.RelationshipsDM
                    .Where(relationship => relationship.RelatedBOHasForeignKey);
            }
        }

        public IList<IDMRelationship> RelationshipsWithFKToBeDeleted { get; private set; }

        public IEnumerable<DMLookupListBusinessObject> AllLookupLists
        {
            get { return this.ClassDM.DMLookupListBusinessObjects; }
        }

        public IList<DMLookupListBusinessObject> LookupListsWithPropsToBeDeleted { get; private set; }

        public IList<DMInheritanceRelationship> InheritanceRelationshipsToBeDeleted { get; private set; }

        public DMClassDeleter(IDMClass dmClass)
        {
            if (dmClass == null) throw new ArgumentNullException("dmClass");
            this.ClassDM = dmClass;
            RelationshipsWithFKToBeDeleted = new List<IDMRelationship>();
            LookupListsWithPropsToBeDeleted = new List<DMLookupListBusinessObject>();
            InheritanceRelationshipsToBeDeleted = new List<DMInheritanceRelationship>();
        }

        /// <summary>
        /// Deletes the <see cref="ClassDM"/> and <br/>
        /// <li>all its related <see cref="DMClass.RelationshipsDM"/></li>
        /// <li>all the DMProperties even if they have Lookup Lists related to the Property i.e.
        ///  <see cref="DMClass.DMLookupListBusinessObjects"/></li>
        /// <li>All Inheritance Relationships</li>
        /// </summary>
        public void DeleteAll()
        {
            this.MarkAllRelationshipsFKsToBeDeleted();
            this.MarkAllLookupListsPropsToBeDeleted();
            this.MarkAllSubClassInheritanceRelationshipsToBeDeleted();
            this.Delete();
        }

        /// <summary>
        /// Deletes the DMClass and all its Related Business Objects and persists these deletes to the datastore.
        /// Note_ that this does not cascade the delete to all the DMClasses relationships
        /// that are marked as Prevent delete i.e. Relationships and Some Relationships of this
        /// DMClasses DMProps unless they have been added to the RelationshipsWithFKToBeDeleted collection 
        /// , the LookupListsWithPropsToBeDeleted and ????? TODO.
        /// If you want to delete the DMClass regardless of these constraints then 
        /// Please use <see cref="DeleteAll"/>
        /// </summary>
        public void Delete()
        {
            MarkForDelete();
            this.ClassDM.Save();
        }

        /// <summary>
        /// Marks the DMClass and all its <see cref="RelationshipsWithFKToBeDeleted"/>,
        /// <see cref="LookupListsWithPropsToBeDeleted"/> and TODO
        /// as Deleted.
        /// It does not Persist this to the DataStore.
        /// </summary>
        public void MarkForDelete()
        {
            var relPropsToBeDeleted = this.RelationshipsWithFKToBeDeleted
                .SelectMany(relationship => relationship.RelationshipProperties);
            foreach (var relationshipProperty in relPropsToBeDeleted.ToList())
            {
                new DMRelationshipPropertyDeleter(relationshipProperty).Delete();
            }
            foreach (var dmRelationship in this.ClassDM.RelationshipsDM.ToArray())
            {
                dmRelationship.MarkForDelete();
            }
            var lookupPropsToBeDeleted = this.LookupListsWithPropsToBeDeleted
                .Select(o => o.DMProperty)
                .Where(prop => prop != null);
            foreach (var prop in lookupPropsToBeDeleted.ToList())
            {
                var uipropsInDMPropToDelete = prop.UIProps.ToArray();
                foreach (var uiProp in uipropsInDMPropToDelete)
                {
                    uiProp.MarkForDelete();
                }
                new DMPropertyDeleter(prop).MarkForDelete();
            }
            foreach (var lookupList in this.ClassDM.DMLookupListBusinessObjects.ToArray())
            {
                lookupList.MarkForDelete();
            }
            if (this.ClassDM.UniqueConstraints != null)
            {
                foreach (var uniqueConstraint in this.ClassDM.UniqueConstraints.ToArray())
                {
                    uniqueConstraint.MarkForDelete();
                }
            }
            var inheritanceRelsToBeDeleted = this.InheritanceRelationshipsToBeDeleted;
            foreach (var inheritanceRelationship in inheritanceRelsToBeDeleted)
            {
                inheritanceRelationship.MarkForDelete();
            }
            this.ClassDM.MarkForDelete();
        }

        /// <summary>
        /// Generally Based on Some User Interface the user can select which 
        /// </summary>
        /// <param name="relationship"></param>
        public void AddRelationshipWithFKToBeDeleted(IDMRelationship relationship)
        {
            RelationshipsWithFKToBeDeleted.Add(relationship);
        }

        public void AddLookupListsWithPropsToBeDeleted(DMLookupListBusinessObject lookupList)
        {
            LookupListsWithPropsToBeDeleted.Add(lookupList);
        }

        /// <summary>
        /// Adds all the relationships with Foreign Keys to the RelationshipsWithFKToBeDeleted collection
        /// </summary>
        public void MarkAllRelationshipsFKsToBeDeleted()
        {
            foreach (var relationship in AllRelationshipWithRelatedFKs)
            {
                this.AddRelationshipWithFKToBeDeleted(relationship);
            }
        }

        /// <summary>
        /// Adds all the LookupListsProps  to the LookupListsWithPropsToBeDeleted collection
        /// </summary>
        public void MarkAllLookupListsPropsToBeDeleted()
        {
            foreach (var lookupList in AllLookupLists)
            {
                this.AddLookupListsWithPropsToBeDeleted(lookupList);
            }
        }

        public void MarkAllSubClassInheritanceRelationshipsToBeDeleted()
        {
            foreach (var subClassRelationship in this.ClassDM.SubClassRelationships)
            {
                this.AddInheritanceRelationshipToBeDeleted(subClassRelationship);
            }
        }

        public void AddInheritanceRelationshipToBeDeleted(DMInheritanceRelationship inheritanceRelationshipToBeDeleted)
        {
            this.InheritanceRelationshipsToBeDeleted.Add(inheritanceRelationshipToBeDeleted);
        }
    }
}